import numpy as np
import pandas
from sklearn.metrics import accuracy_score
from matplotlib import pyplot as plt
train=r"田字型散点\train.csv"
test=r"田字型散点\test.csv"

file_train= pandas.read_csv(train,header=None)
file_test= pandas.read_csv(test,header=None)
#转置 行换成列
data_1= np.array(file_train).transpose([1,0])
data = np.delete(data_1, 2, axis=1)

tian_train= np.array(file_train)
all_y_trues1 = tian_train[2]
#将标签行抽出来
tian_test= np.array(file_test)
all_y_trues2 = tian_test[2]


#激活函数的选择
def sigmoid(x):
    # 第一层到第二层的激活函数
    return 1 / (1 + np.exp(-x))


def deriv_sigmoid(x):
    # 第一层到第二层的激活函数的求导函数
    fx = sigmoid(x)
    return fx * (1 - fx)


def mse_loss(y_true, y_pred):
    # 使用方差作为损失函数
    return ((y_true - y_pred) ** 2).mean()

class NeuralNetwork:
    def __init__(self):
        #权重
        # 第一层
        self.w1 = np.random.normal()
        self.w2 = np.random.normal()
        self.w3 = np.random.normal()
        self.w4 = np.random.normal()
        # 第二层
        self.w5 = np.random.normal()
        self.w6 = np.random.normal()
        self.w7 = np.random.normal()
        self.w8 = np.random.normal()
        # 第三层
        self.w9 = np.random.normal()
        self.w10 = np.random.normal()
        self.w11 = np.random.normal()
        self.w12 = np.random.normal()

        # 截距项
        self.b1 = np.random.normal()
        self.b2 = np.random.normal()
        self.b3 = np.random.normal()

    # 前向传播学习
    def feedforward(self, x):
        h1 = sigmoid(self.w1 * x[0] + self.w2 * x[1] + self.w3 * (x[0] ** 2) + self.w4 * (x[1] ** 2) + self.b1)
        h2 = sigmoid(self.w5 * x[0] + self.w6 * x[1] + self.w7 * (x[0] ** 2) + self.w8 * (x[1] ** 2) + self.b2)
        o1 = sigmoid(self.w9 * h1 + self.w10 * h2 + self.w11 * (h1 ** 2) + self.w12 * (h2 ** 2) + self.b3)
        return o1

    # 训练函数
    def train(self, data, all_y_trues):

        learn_rate = 0.011# 学习率
        epochs = 5000  # 训练的次数

        # 开始训练
        for epoch in range(epochs):
            for x, y_true in zip(data, all_y_trues):
                # 计算h1
                sum_h1 = self.w1 * x[0] + self.w2 * x[1] + self.w3 * (x[0] ** 2) + self.w4 * (x[1] ** 2) + self.b1
                h1 = sigmoid(self.w1 * x[0] + self.w2 * x[1] + self.w3 * (x[0] ** 2) + self.w4 * (x[1] ** 2) + self.b1)
                # 计算h2
                sum_h2 = self.w5 * x[0] + self.w6 * x[1] + self.w7 * (x[0] ** 2) + self.w8 * (x[1] ** 2) + self.b2
                h2 = sigmoid(sum_h2)
                # 计算输出节点
                sum_o1 = self.w9 * h1 + self.w10 * h2 + self.w11 * (h1 ** 2) + self.w12 * (h2 ** 2) + self.b3
                o1 = sigmoid(sum_o1)
                y_pred = o1
                # 反向传播计算导数
                d_L_d_ypred = -2 * (y_true - y_pred)

                #o1
                d_ypred_d_w9 = h1 * deriv_sigmoid(sum_o1)
                d_ypred_d_w10 = h2 * deriv_sigmoid(sum_o1)
                d_ypred_d_w11 = (h1 ** 2) * deriv_sigmoid(sum_o1)
                d_ypred_d_w12 = (h2 ** 2) * deriv_sigmoid(sum_o1)

                d_ypred_d_b3 = deriv_sigmoid(sum_o1)
                d_ypred_d_h1 = (self.w9 * h1 + self.w11 * (h1 ** 2) ) * deriv_sigmoid(sum_o1)
                d_ypred_d_h2 = (self.w10 * h2 + self.w12 * (h2 ** 2)) * deriv_sigmoid(sum_o1)


                #h1
                d_h1_d_w1 = x[0] * deriv_sigmoid(sum_h1)
                d_h1_d_w2 = x[1] * deriv_sigmoid(sum_h1)
                d_h1_d_w3 = (x[0] ** 2) * deriv_sigmoid(sum_h1)
                d_h1_d_w4 = (x[1] ** 2) * deriv_sigmoid(sum_h1)
                d_h1_d_b1 = deriv_sigmoid(sum_h1)

                #h2
                d_h2_d_w5 = x[0] * deriv_sigmoid(sum_h2)
                d_h2_d_w6 = x[1] * deriv_sigmoid(sum_h2)
                d_h2_d_w7 = (x[0] ** 2) * deriv_sigmoid(sum_h2)
                d_h2_d_w8 = (x[1] ** 2) * deriv_sigmoid(sum_h2)
                d_h2_d_b2 = deriv_sigmoid(sum_h2)

                # 梯度下降法
                #h1
                self.w1 -= learn_rate * d_L_d_ypred * d_ypred_d_h1 * d_h1_d_w1
                self.w2 -= learn_rate * d_L_d_ypred * d_ypred_d_h1 * d_h1_d_w2
                self.w3 -= learn_rate * d_L_d_ypred * d_ypred_d_h1 * d_h1_d_w3
                self.w4 -= learn_rate * d_L_d_ypred * d_ypred_d_h1 * d_h1_d_w4
                self.b1 -= learn_rate * d_L_d_ypred * d_ypred_d_h1 * d_h1_d_b1

                #h2
                self.w5 -= learn_rate * d_L_d_ypred * d_ypred_d_h2 * d_h2_d_w5
                self.w6 -= learn_rate * d_L_d_ypred * d_ypred_d_h2 * d_h2_d_w6
                self.w7 -= learn_rate * d_L_d_ypred * d_ypred_d_h2 * d_h2_d_w7
                self.w8 -= learn_rate * d_L_d_ypred * d_ypred_d_h2 * d_h2_d_w8
                self.b2 -= learn_rate * d_L_d_ypred * d_ypred_d_h2 * d_h2_d_b2

                #o1
                self.w9 -= learn_rate * d_L_d_ypred * d_ypred_d_w9
                self.w10 -= learn_rate * d_L_d_ypred * d_ypred_d_w10
                self.w11 -= learn_rate * d_L_d_ypred * d_ypred_d_w11
                self.w12 -= learn_rate * d_L_d_ypred * d_ypred_d_w12
                self.b3 -= learn_rate * d_L_d_ypred * d_ypred_d_b3

            # 计算损失函数 并输出
            if epoch % 10 == 0:
                y_preds = np.apply_along_axis(self.feedforward, 1, data)
                loss = mse_loss(all_y_trues, y_preds)
                #print("Epoch %d loss: %.3f" % (epoch, loss))





# 训练数据
network = NeuralNetwork()
network.train(data, all_y_trues1)


# 真实值与预测值对比
y_preds = np.apply_along_axis(network.feedforward, 1, data)
y_pred = np.around(y_preds,0).astype(int)

y_pred=np.array(y_pred)
#y_pred1=[]
#for i in range(len(all_y_trues2)):
     #y_pred1.append(y_pred1)




print('ACC:',accuracy_score(all_y_trues1, y_pred))
#print('ACC:',accuracy_score(all_y_trues2, y_pred1))

